# -*- coding: utf-8 -*-
"""
用户意图识别分类器 - 基于关键词匹配方案

@author: AI Assistant
"""
import re
import jieba
from typing import Dict, Any, List, Tuple, Optional
from loguru import logger


class IntentClassifier:
    """用户意图分类器（关键词匹配方案）"""
    
    # 意图类型常量
    INTENT_RAINFALL = "rainfall_scenario"
    INTENT_PARAMETER = "parameter_modification"
    INTENT_UNKNOWN = "unknown"
    
    # 降雨假拟方式（英文）
    METHOD_PROPORTIONAL = "proportional"  # 按比例调整（等比例放大）
    METHOD_AVERAGE = "average"  # 平均分配（平均放大）
    
    def __init__(self):
        """初始化分类器"""
        # 降雨相关关键词
        self.rainfall_keywords = [
            "降雨", "降水", "雨量", "假拟降雨",  "模拟降雨", 
            "降雨量", "降水量", "雨", "下雨", "降水总量", 
            "区域降雨", "流域降雨"
        ]
        
        # 假拟方式关键词
        self.proportional_keywords = ["按比例", "等比例", "比例放大", "比例调整", "比例增加", "等比"]
        self.average_keywords = ["平均", "均匀", "平均分配", "平均增加", "均匀分配", "平均分布"]
        
        # 数值提取相关关键词
        self.target_keywords = ["到", "至", "为", "成"]  # 目标值关键词
        self.increment_keywords = ["增加", "提高", "增长", "提升", "加", "增至", "提至"]  # 增量关键词
        
        logger.info("✅ 意图分类器初始化成功")
    
    def predict(self, text: str, para_schema: Dict[str, Any]) -> Dict[str, Any]:
        """
        预测用户意图
        
        Args:
            text: 用户输入文本
            para_schema: 参数模式定义
            
        Returns:
            {
                "intent_type": "rainfall_scenario" | "parameter_modification" | "unknown",
                "confidence": float (0-1),
                "details": dict (额外信息)
            }
        """
        # 分词
        words = list(jieba.cut(text))
        logger.debug(f"分词结果: {words}")
        
        # 提取所有参数名
        parameter_names = self._extract_parameter_names(para_schema)
        
        # 计算各类型得分
        rainfall_score = self._calculate_rainfall_score(words)
        parameter_score = self._calculate_parameter_score(words, parameter_names)
        
        logger.debug(f"得分 - 降雨: {rainfall_score}, 参数: {parameter_score}")
        
        # 判断意图类型
        confidence_threshold = 0.7
        
        if rainfall_score > parameter_score and rainfall_score >= confidence_threshold:
            return {
                "intent_type": self.INTENT_RAINFALL,
                "confidence": rainfall_score,
                "details": {"score_rainfall": rainfall_score, "score_parameter": parameter_score}
            }
        elif parameter_score >= confidence_threshold:
            return {
                "intent_type": self.INTENT_PARAMETER,
                "confidence": parameter_score,
                "details": {"score_rainfall": rainfall_score, "score_parameter": parameter_score}
            }
        else:
            return {
                "intent_type": self.INTENT_UNKNOWN,
                "confidence": 0.0,
                "details": {"score_rainfall": rainfall_score, "score_parameter": parameter_score}
            }
    
    def extract_rainfall_info(self, text: str, current_rainfall: float = 50.0) -> Dict[str, Any]:
        """
        提取降雨假拟信息
        
        Args:
            text: 用户输入文本
            current_rainfall: 当前降雨量（mm）
            
        Returns:
            {
                "method": "按比例调整" | "平均分配",
                "values": [目标值列表]
            }
        """
        # 识别假拟方式
        method = self._identify_rainfall_method(text)
        
        # 提取数值
        values = self._extract_rainfall_values(text, current_rainfall)
        
        return {
            "method": method,
            "values": values
        }
    
    def _extract_parameter_names(self, para_schema: Dict[str, Any]) -> List[str]:
        """
        从参数模式中提取所有参数名
        
        Args:
            para_schema: 参数模式定义
            
        Returns:
            参数名列表
        """
        parameter_names = []
        
        for category in ["initial_state", "parameters"]:
            if category in para_schema:
                parameter_names.extend(para_schema[category].keys())
        
        return parameter_names
    
    def _calculate_rainfall_score(self, words: List[str]) -> float:
        """
        计算降雨意图得分
        
        Args:
            words: 分词结果
            
        Returns:
            得分 (0-1)
        """
        score = 0.0
        text = "".join(words)
        
        # 检查降雨关键词
        has_rainfall_keyword = False
        for keyword in self.rainfall_keywords:
            if keyword in text:
                score += 0.5  # 提高基础分数
                has_rainfall_keyword = True
                break
        
        # 检查假拟方式关键词
        for keyword in self.proportional_keywords + self.average_keywords:
            if keyword in text:
                score += 0.3
                break
        
        # 检查数值模式（包括带单位和不带单位的）
        # 带单位的数值（xx mm / xx毫米）
        if re.search(r'\d+\.?\d*\s*(mm|毫米|MM)', text):
            score += 0.3
        # 不带单位但有明确数值的（如"至39,58"）
        elif has_rainfall_keyword and re.search(r'[\d,，]+', text):
            score += 0.3
        
        # 额外加分：简短但明确的表达
        # "至XX" / "到XX" 等明确的目标值表达
        if re.search(r'(至|到|为)\s*\d+', text):
            score += 0.2
        
        # 包含多个数值（可能是多个目标值）
        if len(re.findall(r'\d+\.?\d*', text)) >= 2:
            score += 0.1
        
        return min(score, 1.0)
    
    def _calculate_parameter_score(self, words: List[str], parameter_names: List[str]) -> float:
        """
        计算参数修改意图得分
        
        Args:
            words: 分词结果
            parameter_names: 参数名列表
            
        Returns:
            得分 (0-1)
        """
        score = 0.0
        text = "".join(words)
        text_lower = text.lower()  # 转换为小写用于不区分大小写匹配
        
        # 检查是否包含参数名（不区分大小写）
        for param_name in parameter_names:
            if param_name.lower() in text_lower:
                score += 0.6
                break
        
        # 检查修改动词
        modify_verbs = ["修改", "改", "调整", "设置", "设为", "变为", "改为", "调为"]
        for verb in modify_verbs:
            if verb in text:
                score += 0.2
                break
        
        # 检查是否有数值
        if re.search(r'\d+\.?\d*', text):
            score += 0.2
        
        return min(score, 1.0)
    
    def _identify_rainfall_method(self, text: str) -> str:
        """
        识别降雨假拟方式
        
        Args:
            text: 用户输入文本
            
        Returns:
            "按比例调整" 或 "平均分配"
        """
        # 检查按比例关键词
        for keyword in self.proportional_keywords:
            if keyword in text:
                return self.METHOD_PROPORTIONAL
        
        # 检查平均分配关键词
        for keyword in self.average_keywords:
            if keyword in text:
                return self.METHOD_AVERAGE
        
        # 默认返回按比例调整
        return self.METHOD_PROPORTIONAL
    
    def _extract_rainfall_values(self, text: str, current_rainfall: float) -> List[float]:
        """
        提取降雨目标值
        
        Args:
            text: 用户输入文本
            current_rainfall: 当前降雨量
            
        Returns:
            目标值列表
        """
        values = []
        
        # 移除单位，统一处理，处理各种变体
        text_normalized = text.replace("毫米", "mm").replace("MM", "mm").replace("Mm", "mm")
        # 移除"P"前缀（如P39mm表示降雨量39mm）
        text_normalized = re.sub(r'P(\d)', r'\1', text_normalized)
        # 统一分隔符
        text_normalized = text_normalized.replace('，', ',').replace('：', ':')
        
        # 模式1: 目标值模式 - 支持多种表达方式
        # 1.0: 百分比目标值 "增加到110%" / "变为150%" / "调整为100%，120%和150%"（支持多个百分比）
        # 检查是否有"到/至/为"+ 百分比的模式
        has_target_keyword = ('到' in text_normalized or '至' in text_normalized or '为' in text_normalized)
        has_percent = ('%' in text or '％' in text)
        
        if has_target_keyword and has_percent:
            percent_target_pattern = r'(\d+\.?\d*)\s*[%％]'
            matches = re.findall(percent_target_pattern, text_normalized)
            if matches:
                for match in matches:
                    percent = float(match)
                    target_value = current_rainfall * (percent / 100)
                    logger.debug(f"百分比目标值: {percent}%, 当前{current_rainfall}mm → 目标{target_value}mm")
                    values.append(target_value)
                return values
        
        # 1.1: 范围表达优先（避免被通用模式误匹配）"X至Y范围" / "从X到Y" / "X-Y"
        range_patterns = [
            r'(\d+\.?\d*)[\s]*(?:到|至)[\s]*(\d+\.?\d*)[\s]*(?:mm|毫米)?[\s]*(?:范围|区间|之间)',  # "39至58mm范围"
            r'(?:从|自)[\s]*(\d+\.?\d*)[\s]*(?:到|至|-|~)[\s]*(\d+\.?\d*)',  # "从39到58"
            r'(\d+\.?\d*)[\s]*[-~][\s]*(\d+\.?\d*)[\s]*(?:mm|毫米)(?!和)',  # "39-58mm"（但不是"39-58mm和..."）
        ]
        for pattern in range_patterns:
            match = re.search(pattern, text_normalized)
            if match:
                start_val = float(match.group(1))
                end_val = float(match.group(2))
                logger.debug(f"模式1.1范围提取: {start_val} 到 {end_val}")
                values.extend([start_val, end_val])
                return values
        
        # 1.2: "至/到/为" + 数字列表（支持多个"数字+单位"组合）
        # 匹配包含多个数字的长字符串
        target_multi_pattern = r'(?:增加|调整|提高|提升|降低|减少|变|改|假设|假拟|模拟|设为|设置|达到|分配)?(?:到|至|为|成|:|是)\s*([\d.,，、\s和mm毫米]+?)(?:时|的|这|看|会|吗|情况|结果|效果|值|水平|？|\?|$)'
        match = re.search(target_multi_pattern, text_normalized)
        if match:
            numbers_str = match.group(1).strip()
            logger.debug(f"模式1.2捕获的数字字符串: '{numbers_str}'")
            # 移除连接词和单位
            numbers_str = numbers_str.replace('和', ' ').replace('到', ' ').replace('之间', ' ')
            numbers_str = numbers_str.replace('mm', ' ').replace('毫米', ' ')
            # 提取所有数字（包括小数）
            number_matches = re.findall(r'\d+\.?\d*', numbers_str)
            logger.debug(f"提取到的数字: {number_matches}")
            if number_matches:
                values.extend([float(m) for m in number_matches])
                return values
        
        # 模式2: 增量计算
        # 2.1: 百分比增加 "增加110%" / "提高50%" / "增加50%，100%和150%"（支持多个百分比）
        percent_increment_pattern = r'(\d+\.?\d*)\s*[%％]'
        # 检查是否包含增量关键词
        has_increment_keyword = any(keyword in text_normalized for keyword in ['增加', '提高', '提升', '增长'])
        
        if has_increment_keyword and ('%' in text or '％' in text):
            # 提取所有百分比
            matches = re.findall(percent_increment_pattern, text_normalized)
            if matches:
                for match in matches:
                    percent = float(match)
                    target_value = current_rainfall * (1 + percent / 100)
                    logger.debug(f"百分比增量: {percent}%, 当前{current_rainfall}mm → 目标{target_value}mm")
                    values.append(target_value)
                return values
        
        # 2.2: "比当前多XX" / "比现在多XX"
        compare_increment_pattern = r'(?:比|较)(?:当前|现在|目前)(?:多|增加|提高)\s*(\d+\.?\d*)\s*(?:mm|毫米)?'
        match = re.search(compare_increment_pattern, text_normalized)
        if match:
            increment = float(match.group(1))
            target_value = current_rainfall + increment
            values.append(target_value)
            return values
        
        # 2.3: "增加XX" / "提高XX"（无"到/至"，无百分号）
        increment_pattern = r'(?:增加|提高|提升|加(?!拟)|多)\s*(?:个)?\s*(\d+\.?\d*)\s*(?:mm|毫米)?(?:左右)?'
        matches = re.findall(increment_pattern, text_normalized)
        if matches and '到' not in text and '至' not in text and '为' not in text and '%' not in text and '％' not in text:
            for match in matches:
                increment = float(match)
                target_value = current_rainfall + increment
                values.append(target_value)
            return values
        
        # 模式3: 减量计算
        # 3.1: 百分比减少 "减少20%" / "降低30%" / "减少20%，30%和50%"（支持多个百分比）
        percent_decrement_pattern = r'(\d+\.?\d*)\s*[%％]'
        # 检查是否包含减量关键词
        has_decrement_keyword = any(keyword in text_normalized for keyword in ['减少', '降低', '减', '下降'])
        
        if has_decrement_keyword and ('%' in text or '％' in text):
            # 提取所有百分比
            matches = re.findall(percent_decrement_pattern, text_normalized)
            if matches:
                for match in matches:
                    percent = float(match)
                    target_value = current_rainfall * (1 - percent / 100)
                    logger.debug(f"百分比减量: {percent}%, 当前{current_rainfall}mm → 目标{target_value}mm")
                    values.append(max(0, target_value))  # 确保不为负
                return values
        
        # 3.2: "减少40mm" - 绝对值减量
        decrement_pattern = r'(?:减少|降低|减)\s*(?:个)?\s*(\d+\.?\d*)\s*(?:mm|毫米)?(?:左右)?'
        matches = re.findall(decrement_pattern, text_normalized)
        if matches and '到' not in text and '至' not in text and '为' not in text and '%' not in text and '％' not in text:
            for match in matches:
                decrement = float(match)
                target_value = current_rainfall - decrement
                values.append(max(0, target_value))  # 确保不为负
            return values
        
        # 模式4: 多个目标值的兜底识别
        # 提取所有数字（如果包含降雨关键词且有多个数字）
        all_numbers = re.findall(r'\d+\.?\d*', text_normalized)
        if len(all_numbers) >= 2 and any(keyword in text for keyword in self.rainfall_keywords):
            # 过滤合理的降雨量范围
            for num_str in all_numbers:
                value = float(num_str)
                if 0 <= value < 1000:  # 合理的降雨量范围（包括0）
                    values.append(value)
            if len(values) >= 2:
                return sorted(list(set(values)))
        
        # 模式5: 简单的数值提取（最后的兜底方案）
        simple_pattern = r'(\d+\.?\d*)\s*(?:mm|毫米)?'
        matches = re.findall(simple_pattern, text_normalized)
        if matches and any(keyword in text for keyword in self.rainfall_keywords):
            for match in matches:
                value = float(match)
                if 0 <= value <= 1000:  # 合理的降雨量范围（包括0和1000）
                    values.append(value)
        
        # 去重并排序
        if values:
            values = sorted(list(set(values)))
            return values
        
        # 如果完全没提取到，返回当前值
        return [current_rainfall]


if __name__ == "__main__":
    # 测试用例
    classifier = IntentClassifier()
    
    test_cases = [
        ("降雨按比例增加到50mm", {"initial_state": {"SA0": {}}, "parameters": {"K": {}}}),
        ("平均分配降雨到60mm", {"initial_state": {"SA0": {}}, "parameters": {"K": {}}}),
        ("将SA0修改为10", {"initial_state": {"SA0": {}}, "parameters": {"K": {}}}),
        ("K减少0.1", {"initial_state": {"SA0": {}}, "parameters": {"K": {}}}),
        ("今天天气怎么样", {"initial_state": {"SA0": {}}, "parameters": {"K": {}}}),
    ]
    
    print("\n=== 意图识别测试 ===")
    for text, schema in test_cases:
        result = classifier.predict(text, schema)
        print(f"\n输入: {text}")
        print(f"意图: {result['intent_type']}, 置信度: {result['confidence']:.2f}")
        
        if result['intent_type'] == classifier.INTENT_RAINFALL:
            rainfall_info = classifier.extract_rainfall_info(text, current_rainfall=50.0)
            print(f"假拟方式: {rainfall_info['method']}")
            print(f"目标值: {rainfall_info['values']}")

